﻿using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using NiuX.Dapper.Quotes;

namespace NiuX.Dapper.Visitors;

public class SelectExpressionVisitor<T> : DbExpressionVisitor
{
    public StringBuilder ConditionSql = new();


    public ISqlQuote SqlQuote { get; set; }

    protected override Expression VisitMember(MemberExpression node)
    {
        ConditionSql.Append(node.Member.Name);
        return node;
    }

    protected override Expression VisitMemberInit(MemberInitExpression node)
    {

        foreach (var binding in node.Bindings.Select(x => (MemberAssignment)x))
        {
            //ConditionSql.Append(binding.Member.Name);


            switch (binding.Expression.NodeType)
            {
                case ExpressionType.Constant:
                    var constantExpression = (ConstantExpression)binding.Expression;
                    ConditionSql.Append($"{constantExpression.Value} AS {SqlQuote.OpenQuote}{binding.Member.Name}{SqlQuote.CloseQuote}");
                    break;
                case ExpressionType.MemberAccess:
                    var constantValue = ((MemberExpression)binding.Expression);
                    var name = constantValue.Member.GetCustomAttribute<ColumnAttribute>()?.Name ?? constantValue.Member.Name;
                    ConditionSql.Append($"{SqlQuote.OpenQuote}{name}{SqlQuote.CloseQuote} AS {SqlQuote.OpenQuote}{binding.Member.Name}{SqlQuote.CloseQuote}");
                    break; ;
            }


            ConditionSql.Append(",");
        }
        ConditionSql.RemoveLastChar();

        return node;
    }

    public override string Resolve(Expression expression)
    {
        if (expression is Expression<Func<T, T>> exp)
        {
            Visit(exp.Body);
            return ConditionSql.ToString();
        }

        return "";
    }

}

public class SelectExpressionVisitor<T, TResult> : SelectExpressionVisitor<T>
{



    public override string Resolve(Expression expression)
    {
        if (expression is Expression<Func<T, TResult>> exp)
        {
            Visit(exp.Body);
            return ConditionSql.ToString();
        }

        return "";
    }
}